// Copyright (c) 2025 Huawei Technologies Co., Ltd.
// openUBMC is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
//         http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
//
// Description: scsi命令处理

#ifndef SCSI_PROCESSOR_HPP
#define SCSI_PROCESSOR_HPP

#include <cstdint>
#include <cstring>
#include <string>
#include <vector>
#include <iostream>
#include <stdexcept>
#include <functional>
#include "PackData.hpp"
#include "ImageDevice.hpp"
#include "VMMMessage.hpp"

namespace ScsiCommand {
    // SCSI命令字
    constexpr uint8_t FORMAT_UNIT = 0x04;
    constexpr uint8_t INQUIRY = 0x12;
    constexpr uint8_t START_STOP = 0x1B;
    constexpr uint8_t MODE_SELECT = 0x55;
    constexpr uint8_t MODE_SENSE = 0x5A;
    constexpr uint8_t PREVENT_ALLOW_MEDIUM_REMOVAL = 0x1E;
    constexpr uint8_t READ_10 = 0x28;
    constexpr uint8_t READ_12 = 0xA8;
    constexpr uint8_t READ_CAPACITY = 0x25;
    constexpr uint8_t READ_FORMAT_CAPACITY = 0x23;
    constexpr uint8_t REQUEST_SENSE = 0x03;
    constexpr uint8_t REZERO_UNIT = 0x01;
    constexpr uint8_t SEEK_10 = 0x2B;
    constexpr uint8_t SEND_DIAGNOSTIC = 0x1D;
    constexpr uint8_t TEST_UNIT_READY = 0x00;
    constexpr uint8_t TEST_UNIT_READY_EXP = 0x4A;
    constexpr uint8_t VERIFY = 0x2F;
    constexpr uint8_t WRITE_10 = 0x2A;
    constexpr uint8_t WRITE_12 = 0xAA;
    constexpr uint8_t WRITE_AND_VERIFY = 0x2E;
    constexpr uint8_t MECHANISM_STATUS = 0xBD;
    constexpr uint8_t READ_CD = 0xBE;
    constexpr uint8_t READ_CD_MSF = 0xB9;
    constexpr uint8_t READ_HEADER = 0x44;
    constexpr uint8_t READ_SUB_CHANNEL = 0x42;
    constexpr uint8_t READ_TOC = 0x43;
    constexpr uint8_t STOP_PLAY_SCAN = 0x4e;
}

namespace ScsiSenseKey {
    // SCSI状态位
    constexpr uint8_t NO_SENSE = 0x00;
    constexpr uint8_t RECOVERED_ERROR = 0x01;
    constexpr uint8_t NOT_READY = 0x02;
    constexpr uint8_t MEDIUM_ERROR = 0x03;
    constexpr uint8_t HARDWARE_ERROR = 0x04;
    constexpr uint8_t ILLEGAL_REQUEST = 0x05;
    constexpr uint8_t UNIT_ATTENTION = 0x06;
    constexpr uint8_t DATA_PROTECT = 0x07;
    constexpr uint8_t BLANK_CHECK = 0x08;
}

namespace ScsiAsc {
    // SCSI附加状态码
    constexpr uint8_t NO_ADDITIONAL_SENSE = 0x00;
    constexpr uint8_t INVALID_FIELD_IN_CDB = 0x24;
    constexpr uint8_t INVALID_COMMAND_OPERATION_CODE = 0x20;
    constexpr uint8_t LOGICAL_UNIT_NOT_READY = 0x04;
    constexpr uint8_t WRITE_PROTECTED = 0x27;
    constexpr uint8_t MEDIUM_NOT_PRESENT = 0x3A;
    constexpr uint8_t MEDIUM_CHANGE = 0x28;
    constexpr uint8_t INCOMPATIBLE_MEDIUM_INSTALLED = 0x30;
    constexpr uint8_t ID_CRC_OR_ECC_ERROR = 0x10;
    constexpr uint8_t LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE = 0x21;
}

namespace ScsiDataType {
    constexpr uint8_t COMMAND = 0;
    constexpr uint8_t DATA = 1;
}

namespace ScsiDataState {
    constexpr uint8_t CONTINUE = 1;
    constexpr uint8_t END = 3;
}

constexpr int MAX_PACKET_SIZE = 32768;
constexpr int PACKET_HEAD_SIZE = 8;
constexpr int MODE_SENSE_DATA_SIZE = 8;
constexpr int MAX_TOC_DATA_SIZE = 48;       // TOC数据最大长度，包括4字节TOC头，后续最多跟随4个TOC track（format2），一个TOC track包括11字节数据
constexpr int READ_ERR_LIMIT = 2;
constexpr int READ_BUFFER_SIZE = 0x20000;   // 128K

class ScsiProcessor {
public:
    explicit ScsiProcessor(ImageDevice& imageDevice);
    ~ScsiProcessor();

    void SetSendHandler(std::function<void(const std::vector<uint8_t>&)> handler);
    void SetLogHandler(std::function<void(const std::string&)> handler);

    void SetSenseKey(uint8_t senseKey, uint8_t asc, uint8_t ascq, int info);
    void CommandFinish(uint8_t cmd);

    void SendData(const std::vector<uint8_t>&, int dataLength, bool isLast);

    void ProcessScsiCommand(VMMMessage vmmMsg);

private:
    std::function<void(const std::vector<uint8_t>&)> sendHandler_;
    std::function<void(const std::string&)> logHandler_;

    ImageDevice& imageDevice_; // 处理大容量存储设备的类

    // SCSI 状态信息（Sense Data）
    std::vector<uint8_t> senseKey_ = {0x70, 0, 0, 0x06, 0, 0, 0, 0x0a, 0, 0, 0, 0, 0x29, 0, 0, 0, 0, 0};
    // SCSI INQUIRY 命令的响应数据
    std::vector<uint8_t> inquiryData_ = {0x05, 0x80, 0, 0x21, 0x1F, 0, 0, 0, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6C,
        0x20, 0x44, 0x56, 0x44, 0x2D, 0x52, 0x4F, 0x4D, 0x20, 0x56, 0x4D, 0x20, 0x31, 0x2E, 0x31, 0x2E, 0x30, 0x20,
        0x32, 0x32, 0x35};
    // SCSI READ FORMAT CAPACITIES 命令的响应数据
    std::vector<uint8_t> formatCapacityData_ = {0, 0, 0, 0x10, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0x0b, 0x40, 0, 0, 2, 0};
    
    uint8_t cmdId = 0;
    int cacheBlockNum = 0;
    unsigned long long cacheLba = 0;
    std::vector<uint8_t> dataBuffer_;
    int readErrNum = 0;
    unsigned long long readErrAreaBegin = 0;
    unsigned long long readErrAreaEnd = 0;

    void ModeSense(const std::vector<uint8_t>& data);
    void TestUnitReady();
    void StartStop(const std::vector<uint8_t>& data);
    void Read(const std::vector<uint8_t>& data);
    int ReadBlockData(unsigned long long lba, int blockNum, bool cache);
    void ReadToc(const std::vector<uint8_t>& data);
    int ReadTocFormat0(std::vector<uint8_t>& tocData, bool isMSF, int startTrack);
    int ReadTocFormat1(std::vector<uint8_t>& tocData);
    int ReadTocFormat2(std::vector<uint8_t>& tocData, bool isMSF);
    void ReadCapacity();
    void ReadFormatCapacity();
};

#endif // SCSI_PROCESSOR_HPP